/*
    SHM 共享内存读写
    父进程负责写 子进程负责读
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <signal.h>

#define NAME "/my_shm"
#define SIZE 1024

char *child_ptr = NULL;
char *parent_ptr = NULL;
int end_flag = 0;

void r(int sid)
{
    if(child_ptr)
    {
        if(strcmp(child_ptr, "end") == 0)
        {
            printf("子进程收到结束信号，退出。\n");
            end_flag = 1;
            munmap(child_ptr, SIZE);
            exit(0);
        }
        printf("用户输入的信息为:::%s\n", child_ptr);
    }
    else{
        printf("接到读取信号，但是内存未映射！\n");
    }
}

void w(int sid)
{
    printf("请输入信息：\n");
    char buf[1024];
    scanf("%s", buf);
    memset(parent_ptr, 0, SIZE);
    strncpy(parent_ptr, buf, strlen(buf)+1);
    if(strcmp(buf, "end") == 0)
    {
        end_flag = 1;
    }
}

int main()
{
    // 打开
    int fd = shm_open(NAME, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
    if(fd == -1)
    {
        perror("创建共享内存失败!\n");
        exit(1);
    }
    // 开空间
    int ret = ftruncate(fd, SIZE);
    if(ret == -1)
    {
        perror("空间分配失败！\n");
        close(fd);
        exit(1);
    }
    int pid = fork();
    if(pid == -1)
    {
        perror("创建进程失败！\n");
        exit(1);
    }
    if(pid == 0)
    {
        // 子进程的逻辑
        // 子进程负责读
        signal(SIGUSR1, r);
        int child_fd = shm_open(NAME, O_RDONLY, 0666);
        child_ptr = mmap(NULL, SIZE, PROT_READ, MAP_SHARED, child_fd, 0);
        if(child_ptr == MAP_FAILED)
        {
            perror("内存映射失败！\n");
            close(fd);
            exit(1);
        }
        // 输入end 进程结束
        while(!end_flag)
        {
            pause();
            kill(getppid(), SIGUSR1);
        }
        munmap(child_ptr, SIZE);
        close(fd);
    }
    else{
        // 父进程的逻辑
        // 内存映射
        signal(SIGUSR1, w);
        parent_ptr = mmap(NULL, SIZE, PROT_WRITE, MAP_SHARED, fd, 0);
        if(parent_ptr == MAP_FAILED)
        {
            perror("内存映射失败！\n");
            close(fd);
            exit(1);
        }
        w(0);
        kill(pid, SIGUSR1);
        while(!end_flag)
        {
            pause();
            kill(pid, SIGUSR1);
        }
        munmap(parent_ptr, SIZE);
        close(fd);
        shm_unlink(NAME);
    }
    return 0;
}
